package com.hd123.rumba.gwt.widget2.server;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.hd123.gwt.types.JsBigDecimal;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.gwt.base.server.AbstractConverter;
import com.hd123.rumba.gwt.widget2.client.grid.RPageData;
import com.hd123.rumba.sql.biz.BResultPage;

/**
 * 把{@link BResultPage}转换为{@link RPageData}
 * <p>
 * 根据BResultPage和RPageData所包含数据类型的不同，可分为以下几种情况：
 * <p>
 * 
 * <h3>数组 to 数组</h1> <br>
 * 得到BResultPage的HQL语句类似：select a.uuid, a.code, a.name from
 * SomeEnrity a<br>
 * 希望转换后的RPageData.getValues()包含每个元素的是类似[uuid, code,
 * name]这样的对象数组。<br>
 * 这种情况是最原始和笨拙的，所以需要RPageDataConverter的帮助，转换写法为：<br>
 * 
 * <pre>
 * RPageData dest = new RPageDataConverter().convert(source);
 * </pre>
 * 
 * <h3>数组 to B对象</h1><br>
 * 得到BResultPage的HQL语句类似：select a.uuid, a.code, a.name from
 * SomeEnrity a<br>
 * 希望转换后的RPageData.getValues()包含每个元素的是SomeEntiry对应的B对象。<br>
 * 这种情况只需要调用RPageDataConverter的静态方法copyPagingInfo，具体的数据转换应自行完成，
 * 转换写法为：<br>
 * 
 * <pre>
 * RPageData dest = new RPageDate();
 * RPageDataConverter.copyPagingInfo(source, dest);
 * for (Iterator&lt;Object[]&gt; i = source.getValues().iterator; i.hasNext();) {
 *   Object[] sourceRec = i.next();
 *   BSomeEntity destRec = new BSomeEntity();
 *   destRec.setUuid((String) sourceRec[0]);
 *   destRec.setCode((String) sourceRec[1]);
 *   destRec.setName((String) sourceRec[2]);
 *   dest.getValues().add(destRec);
 * }
 * </pre>
 * 
 * <h3>P对象 to B对象</h1><br>
 * 得到BResultPage的HQL语句类似：select a from SomeEnrity a<br>
 * 希望转换后的RPageData.getValues()包含每个元素的是SomeEntiry对应的B对象。<br>
 * 这种情况只需要调用RPageDataConverter的静态方法copyPagingInfo，具体的数据转换应自行完成，
 * 转换写法为：<br>
 * 
 * <pre>
 * RPageData dest = new RPageDate();
 * RPageDataConverter.copyPagingInfo(source, dest);
 * for (Iterator&lt;SomeEntity&gt; i = source.getValues().iterator; i.hasNext();) {
 *   SomeEntity sourceRec = i.next();
 *   BSomeEntity destRec = new BSomeEntity();
 *   destRec.setUuid(someEntity.getUuid());
 *   destRec.setCode(someEntity.getCode());
 *   destRec.setName(someEntity.getName());
 *   dest.getValues().add(destRec);
 * }
 * </pre>
 * 
 * <h3>P对象 to 数组</h1><br>
 * 得到BResultPage的HQL语句类似：select a from SomeEnrity a<br>
 * 希望转换后的RPageData.getValues()包含每个元素的是类似[uuid, code,
 * name]这样的对象数组。<br>
 * 这种情况只需要调用RPageDataConverter的静态方法copyPagingInfo，具体的数据转换应自行完成，
 * 转换写法为：<br>
 * 
 * <pre>
 * RPageData dest = new RPageDate();
 * RPageDataConverter.copyPagingInfo(source, dest);
 * for (Iterator&lt;SomeEntity&gt; i = source.getValues().iterator; i.hasNext();) {
 *   SomeEntity sourceRec = i.next();
 *   List destField = new ArrayList();
 *   destField.add(sourceRec.getUuid());
 *   destField.add(sourceRec.getCode());
 *   destField.add(sourceRec.getName());
 *   dest.getValues().add(destField);
 * }
 * </pre>
 * 
 * 以上四种转换方式中，"P对象 to B对象"的方式最好，如果P对象字段较多，select a from SomeEntity
 * a 这种写法太慢的话，可以采用"数组 to B对象"的方式。
 * 
 * @author LiQi
 * 
 */
public class RPageDataConverter extends AbstractConverter<BResultPage, RPageData> {

  public RPageData convert(BResultPage source) throws BusinessException {
    if (source == null)
      return null;

    // 分页信息
    RPageData dest = new RPageData();
    copyPagingInfo(source, dest);

    // 逐条记录转换
    List destValues = new ArrayList();
    for (Object sourceRec : source.getValues()) {
      Object[] sourceRecAsArray = sourceRec instanceof Object[] ? (Object[]) sourceRec
          : new Object[] {
            sourceRec };
      List destRec = new ArrayList();

      // 逐个字段转换
      for (Object sourceField : sourceRecAsArray) {
        Object destField = null;
        if (sourceField == null)
          destField = null;
        else if (sourceField instanceof Date)
          destField = convertDate((Date) sourceField);
        else if (sourceField instanceof BigDecimal)
          destField = new JsBigDecimal(((BigDecimal) sourceField).doubleValue());
        else if (sourceField instanceof Enum)
          destField = ((Enum) sourceField).name();
        else
          destField = sourceField;

        destRec.add(destField);
      }
      destValues.add(destRec);
    }

    dest.setValues(destValues);
    return dest;
  }

  /**
   * 把分页信息从BResultPage复制到RPageData
   * 
   * @param source
   * @param dest
   */
  public static void copyPagingInfo(BResultPage source, RPageData dest) {
    dest.setTotalCount(source.getElementCount());
    dest.setPageCount(source.getPageCount());
    dest.setCurrentPage(source.getPage());
  }
}
